﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SaveSation.Entity;
using SaveSation.Utils;
using SaveSation.Common;
using Common.UI;
using DefPack;
using DefPack.Common;

namespace SaveSation
{
    public partial class Form1 : Form
    {
        private AppSetting m_AppSetting;
        private ArchiveEntity m_Archive;
        private BackupEntity m_Backup;
        private bool state = false;
        private int tick = 2000;
        private int maxCount = 0;
        public Form1(AppSetting appSetting, ArchiveEntity entity)
        {
            InitializeComponent();

            try
            {
                this.comboBox1.SelectedIndex = 0;
                this.comboBox2.SelectedIndex = 0;
                this.comboBox3.SelectedIndex = 0;
                this.comboBox4.SelectedIndex = 0;
                this.comboBox5.SelectedIndex = 0;
                m_Archive = entity;
                this.Text = "SaveStation - " + entity.Name;
                m_AppSetting = appSetting;
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            new Thread(threadDemon).Start();
        }
        private void Form1_Shown(object sender, EventArgs e)
        {
            try
            {
                m_Archive.Load();
                m_Backup = new BackupEntity();
                fillSetting();
                this.listViewEx1.Items.Clear();
                foreach (var item in m_Archive.ArchiveItems)
                {
                    ListViewItem it = new ListViewItem("-");
                    it.SubItems.Add(item.Name);
                    it.SubItems.Add(item.Description);
                    it.SubItems.Add(item.CreateTime.ToString());
                    it.SubItems.Add(CommonUtil.GetSizeDesc(item.Length));
                    this.listViewEx1.Items.Add(it);
                }
                updateIndex();
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private bool Save()
        {
            if (m_Archive == null) throw new NullReferenceException();
            if (string.IsNullOrEmpty(m_Archive.FullPath))
            {
                folderBrowserDialog1.ShowNewFolderButton = true;
                folderBrowserDialog1.Description = "请选择文件存储目录：";
                folderBrowserDialog1.ShowNewFolderButton = true;
                folderBrowserDialog1.InitialDirectory = Application.StartupPath;
                folderBrowserDialog1.SelectedPath = "";
                //folderBrowserDialog1.AutoUpgradeEnabled = false;
                if (folderBrowserDialog1.ShowDialog() != DialogResult.OK) return false;
            }
            applySetting();
            return true;
        }
        private void MainMenuItemStart_Click(object sender, EventArgs e)
        {
            bool en = MainMenuItemStart.Text == "停止任务";
            if (en)
            {
                MainMenuItemStart.Text = "开始任务";
                state = false;
                Thread.Sleep(1000);
                this.toolStripStatusLabel1.Text = $"备份已停止：等待备份开始（按Ctrl+F5开始）。";
            }
            else
            {
                Save();
                if (string.IsNullOrEmpty(m_Archive.FullPath))
                {
                    return;
                }
                MainMenuItemStart.Text = "停止任务";
                state = true;
                this.toolStripStatusLabel1.Text = $"准备就绪：下次备份时间 {DateTime.Now.AddMilliseconds(tick)}（按Ctrl+F5停止）。";

            }
            this.groupBox2.Enabled = en;
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            applySetting();
        }
        private void applySetting()
        {
            try
            {
                if (m_Archive == null) m_Archive = new ArchiveEntity();
                m_Archive.Tick = (byte)this.comboBox1.SelectedIndex;
                m_Archive.MaxCount = (byte)this.comboBox2.SelectedIndex;
                m_Archive.TriggerEvent = (byte)this.comboBox3.SelectedIndex;
                m_Archive.BackupContent = (byte)this.comboBox4.SelectedIndex;
                m_Archive.RestoreOperation = (byte)this.comboBox5.SelectedIndex;
                m_Archive.UnDetect = this.textBox5.Text;
                m_Archive.UnBuckup = this.textBox6.Text;
                lock (m_Archive)
                {
                    int f = int.Parse(this.comboBox1.Items[m_Archive.Tick].ToString());
                    tick = f * 1000;
                }
                maxCount = m_Archive.MaxCount;
                if (maxCount == 1)
                {
                    maxCount = 50;
                }
                else if (maxCount == 2)
                {
                    maxCount = 100;
                }
                else if (maxCount == 3)
                {
                    maxCount = 200;
                }
                else if (maxCount == 4)
                {
                    maxCount = 500;
                }
                m_AppSetting.Save(StartForm.m_ConfigFile);
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void fillSetting()
        {
            if (m_Archive == null) m_Archive = new ArchiveEntity();
            this.comboBox1.SelectedIndex = m_Archive.Tick;
            this.comboBox2.SelectedIndex = m_Archive.MaxCount;
            this.comboBox3.SelectedIndex = m_Archive.TriggerEvent;
            this.comboBox4.SelectedIndex = m_Archive.BackupContent;
            if (m_Archive.BackupContent != 1)
            {
                this.comboBox5.SelectedIndex = m_Archive.RestoreOperation;
            }
            else
            {
                this.comboBox5.SelectedIndex = 0;
            }
            this.textBox5.Text = m_Archive.UnDetect;
            this.textBox6.Text = m_Archive.UnBuckup;
            maxCount = m_Archive.MaxCount;
            if (maxCount == 1)
            {
                maxCount = 50;
            }
            else if (maxCount == 2)
            {
                maxCount = 100;
            }
            else if (maxCount == 3)
            {
                maxCount = 200;
            }
            else if (maxCount == 4)
            {
                maxCount = 500;
            }
        }

        private void buttonSelectApplication_Click(object sender, EventArgs e)
        {
            openFileDialog1.Title = "请选择应用程序：";
            openFileDialog1.Filter = "应用程序（*.exe）|*.exe";
            openFileDialog1.Multiselect = false;
            if (openFileDialog1.ShowDialog() != DialogResult.OK) return;
            m_Archive.Application = openFileDialog1.FileName;
        }

        private void buttonSelectArchivePath_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.ShowNewFolderButton = false;
            folderBrowserDialog1.Description = "请选择存档所在目录：";
            if (folderBrowserDialog1.ShowDialog() != DialogResult.OK) return;
            m_Archive.ArchivePath = folderBrowserDialog1.SelectedPath;
        }
        private void updateIndex()
        {
            try
            {
                int i = 1;
                List<string> deleteList = new List<string>();
                List<int> indexList = new List<int>();
                foreach (ListViewItem item in listViewEx1.Items)
                {
                    item.SubItems[0].Text = i.ToString();
                    i++;
                }
            }
            catch (Exception e1)
            {
                e1.Error();
            }
        }
        private void deleteItems()
        {
            try
            {
                int i = 0;
                List<string> deleteList = new List<string>();
                List<int> indexList = new List<int>();
                foreach (ListViewItem item in listViewEx1.Items)
                {
                    if (maxCount != 0 && i >= maxCount)
                    {
                        deleteList.Add(listViewEx1.Items[i].SubItems[1].Text);
                        indexList.Add(i);
                    }
                    i++;
                }
                for (int l = deleteList.Count - 1; l >= 0; l--)
                {
                    File.Delete(m_Archive.FullPath + "\\" + deleteList[l]);
                    listViewEx1.Items.RemoveAt(indexList[l]);
                    m_Archive.ArchiveItems.RemoveAt(indexList[l]);
                }
            }
            catch (Exception e1)
            {
                e1.Error();
            }
        }
        private void threadDemon()
        {
            Thread.CurrentThread.IsBackground = true;
            int mtick = 0;
            while (true)
            {
                Thread.Sleep(1000);
                mtick++;
                if (mtick * 1000 >= tick)
                {
                    if (state)
                        new Thread(threadPolling).Start();
                    mtick = 0;
                }
            }
        }
        private void threadPolling()
        {
            Thread.CurrentThread.IsBackground = true;
            try
            {

                Action<ArchiveItem> action = (item) =>
                {
                    ListViewItem it = new ListViewItem("-");
                    it.SubItems.Add(item.Name);
                    it.SubItems.Add(item.Description);
                    it.SubItems.Add(item.CreateTime.ToString());
                    it.SubItems.Add(CommonUtil.GetSizeDesc(item.Length));
                    this.listViewEx1.Items.Insert(0, it);
                    this.m_Archive.ArchiveItems.Insert(0, item);
                    updateIndex();
                    deleteItems();
                    this.toolStripStatusLabel1.Text = $"准备就绪：存档于 {DateTime.Now} 备份成功，下次备份时间 {DateTime.Now.AddMilliseconds(tick)}（按Ctrl+F5停止）。";
                };
                lock (m_Archive)
                {
                    var list = m_Backup.Polling(m_Archive);
                    if (list.Count > 0)
                    {
                        ArchiveItem item = BackupEntity.Backup(m_Archive, list, $"智能备份({(m_Archive.BackupContent == 0 ? "全量" : "增量")})");
                        this.BeginInvoke(action, item);
                    }
                    else
                    {
                        this.BeginInvoke(() =>
                        {
                            this.toolStripStatusLabel1.Text = $"暂不备份：未检测到文件更新，下次备份时间 {DateTime.Now.AddMilliseconds(tick)}（按Ctrl+F5停止）。";
                        });
                    }
                }
            }
            catch (Exception e1)
            {
                e1.Error();
                try
                {
                    this.BeginInvoke(() =>
                    {
                        this.toolStripStatusLabel1.Text = $"{e1.Message}";
                    });
                }
                catch { }
            }
        }

        private void ListMenuItemRestore_Click(object sender, EventArgs e)
        {
            try
            {
                string file = $"{m_Archive.FullPath}\\{listViewEx1.SelectedItems[0].SubItems[1].Text}";
                var result = MessageBox.Show($"您将要还原此备份，是否在还原时额外备份当前存档？\n\n名称：{listViewEx1.SelectedItems[0].SubItems[1].Text}\n描述：{listViewEx1.SelectedItems[0].SubItems[2].Text}\n时间：{listViewEx1.SelectedItems[0].SubItems[3].Text}", "还原", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (result == DialogResult.Cancel)
                {
                    return;
                }
                else if (result == DialogResult.Yes)
                {
                    lock (m_Archive)
                    {
                        var list = m_Backup.Polling(m_Archive, true);
                        if (list.Count > 0)
                        {
                            ArchiveItem item = BackupEntity.Backup(m_Archive, list, "额外备份(全量)");
                            ListViewItem it = new ListViewItem("-");
                            it.SubItems.Add(item.Name);
                            it.SubItems.Add(item.Description);
                            it.SubItems.Add(item.CreateTime.ToString());
                            it.SubItems.Add(CommonUtil.GetSizeDesc(item.Length));
                            this.listViewEx1.Items.Insert(0, it);
                            this.m_Archive.ArchiveItems.Insert(0, item);
                            updateIndex();
                            if (state) deleteItems();
                        }
                    }
                }
                using (DefPackArchive stream = DefPackArchive.CreateWith(file))
                {
                    if (m_Archive.RestoreOperation == 1)
                    {
                        IEnumerable<string> files = Directory.EnumerateFileSystemEntries(m_Archive.ArchivePath.ExpandEnvironmentVariables(), "*", SearchOption.AllDirectories);
                        foreach (var item in files)
                        {
                            try
                            {
                                if (File.Exists(item))
                                {
                                    File.Delete(item);
                                }
                                if (Directory.Exists(item))
                                {
                                    Directory.Delete(item, true);
                                }
                            }
                            catch (Exception e1)
                            {
                                e1.Error();
                            }
                        }
                    }
                    lock (m_Archive)
                    {
                        stream.DeCompressDirectory("", Path.GetDirectoryName(m_Archive.ArchivePath.ExpandEnvironmentVariables()));
                        m_Backup.Polling(m_Archive);
                    }
                    MessageBox.Show(this, "文件已成功还原。", "操作成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void ListMenuItemView_Click(object sender, EventArgs e)
        {
            string defPack = m_AppSetting.DefPackExe;
            //string defPack = "E:\\Visual Studio\\DefPack.Core\\DefPack.UI\\bin\\Debug\\net6.0-windows\\DefPack.UI.exe";
            if (File.Exists(defPack))
            {
                Process.Start(defPack, $"\"{m_Archive.FullPath}\\{listViewEx1.SelectedItems[0].SubItems[1].Text}\"");
            }
            else
            {
                MessageBox.Show(this, $"无法从以下路径找到指定的文件：\n{defPack}", "文件不存在", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }

        }

        private void ListMenuItemDelete_Click(object sender, EventArgs e)
        {
            lock (m_Archive)
            {
                if (MessageBox.Show($"您确认要删除这 {listViewEx1.SelectedIndices.Count} 个项目吗？", "删除", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK) return;
                for (int i = listViewEx1.SelectedIndices.Count - 1; i >= 0; i--)
                {
                    int j = listViewEx1.SelectedIndices[i];
                    if (File.Exists(m_Archive.ArchiveItems[j].FullName)) File.Delete(m_Archive.ArchiveItems[j].FullName);
                    m_Archive.ArchiveItems.RemoveAt(j);
                    listViewEx1.Items.RemoveAt(j);
                }
                updateIndex();
                MessageBox.Show(this, "删除成功。", "操作成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void ListMenuItemBackup_Click(object sender, EventArgs e)
        {
            lock (m_Archive)
            {
                var list = m_Backup.Polling(m_Archive, true);
                if (list.Count > 0)
                {
                    DialogResult dialogResult = InputForm.Show(out string? note, "请输入备份说明：", "立即备份", "手动备份(全量)");
                    if (dialogResult == DialogResult.Cancel) return;
                    ArchiveItem item = BackupEntity.Backup(m_Archive, list, note);
                    ListViewItem it = new ListViewItem("-");
                    it.SubItems.Add(item.Name);
                    it.SubItems.Add(item.Description);
                    it.SubItems.Add(item.CreateTime.ToString());
                    it.SubItems.Add(CommonUtil.GetSizeDesc(item.Length));
                    this.listViewEx1.Items.Insert(0, it);
                    this.m_Archive.ArchiveItems.Insert(0, item);
                    updateIndex();
                    if (state) deleteItems();
                }
            }
        }

        private void ListMenuItemEditNote_Click(object sender, EventArgs e)
        {
            try
            {
                DialogResult dialogResult = InputForm.Show(out string? note, "请输入备份说明：", "立即备份", listViewEx1.SelectedItems[0].SubItems[2].Text);
                if (dialogResult == DialogResult.Cancel) return;
                lock (m_Archive)
                {
                    foreach (int i in listViewEx1.SelectedIndices)
                    {
                        m_Archive.ArchiveItems[i].Description = note;
                        listViewEx1.Items[i].SubItems[2].Text = note;
                    }
                }
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            bool en = listViewEx1.SelectedItems.Count == 1;
            ListMenuItemRestore.Enabled = en;
            ListMenuItemView.Enabled = en;
            ListMenuItemDelete.Enabled = listViewEx1.SelectedItems.Count > 0;
            ListMenuItemEditNote.Enabled = en;
            ListMenuItemBackup.Enabled = m_Archive.ArchivePath != null;
        }

        private void comboBox5_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox4.SelectedIndex == 1 && comboBox5.SelectedIndex == 1)
            {
                MessageBox.Show(this, $"此模式不适用于{comboBox4.SelectedItem.ToString()}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                comboBox5.SelectedIndex = 0;
            }
        }

        private void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox4.SelectedIndex == 1)
            {
                comboBox5.SelectedIndex = 0;
            }
        }

        private void toolStripMenuItemRunApplication_Click(object sender, EventArgs e)
        {
            try
            {
                if (!File.Exists(m_Archive.Application) && m_Archive.SteamID.IsNullOrEmpty())
                {
                    throw new Exception("请选择应用程序位置或填写StreamID！");
                }
                if (!m_Archive.SteamID.IsNullOrEmpty())
                {
                    Process process = new Process();
                    ProcessStartInfo processStartInfo = new ProcessStartInfo($"Steam://run/{m_Archive.SteamID}/");
                    process.StartInfo = processStartInfo;
                    process.StartInfo.UseShellExecute = true;
                    process.Start();
                }
                else if (File.Exists(m_Archive.Application))
                {
                    Process process = new Process();
                    ProcessStartInfo processStartInfo = new ProcessStartInfo(m_Archive.Application);
                    process.StartInfo = processStartInfo;
                    process.StartInfo.UseShellExecute = true;
                    process.Start();
                }
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void toolStripMenuItemOpenStore_Click(object sender, EventArgs e)
        {
            try
            {
                if (!m_Archive.ArchivePath.IsNullOrEmpty() && Directory.Exists(m_Archive.ArchivePath.ExpandEnvironmentVariables()))
                {
                    Process process = new Process();
                    ProcessStartInfo processStartInfo = new ProcessStartInfo($"{m_Archive.ArchivePath.ExpandEnvironmentVariables()}");
                    process.StartInfo = processStartInfo;
                    process.StartInfo.UseShellExecute = true;
                    process.Start();
                }
                else
                {
                    throw new DirectoryNotFoundException("存档位置为空或不可用！\n\n" + m_Archive.ArchivePath.ExpandEnvironmentVariables());
                }
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void toolStripMenuItemOpenBackupStore_Click(object sender, EventArgs e)
        {
            try
            {
                if (!m_Archive.FullPath.IsNullOrEmpty() && Directory.Exists(m_Archive.FullPath))
                {
                    Process process = new Process();
                    ProcessStartInfo processStartInfo = new ProcessStartInfo($"{m_Archive.FullPath}");
                    process.StartInfo = processStartInfo;
                    process.StartInfo.UseShellExecute = true;
                    process.Start();
                }
                else
                {
                    throw new DirectoryNotFoundException("目录位置为空或不可用！\n\n" + m_Archive.FullPath);
                }
            }
            catch (Exception e1)
            {
                e1.Error();
                MessageBox.Show(this, e1.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
    public class ListViewEx : ListView
    {
        public ListViewEx()
        {
            SetStyle(ControlStyles.DoubleBuffer |
            ControlStyles.OptimizedDoubleBuffer |
            ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();
        }
    }
}
